<?php

namespace app\api\controller;

use app\common\model\card\{Card, CardWorldfirstNotify};
use app\common\model\finance\{TransactionNotification};

class WorldFirstController extends BaseApiController
{
    public array $notNeedLogin = ['notifyBillResult', 'notifyBillResult_hk'];

    function sign($data, $privateKey)
    {
        if (!openssl_sign($data, $signature, $privateKey, OPENSSL_ALGO_SHA256)) {
            throw new Exception("签名失败");
        }
        return $signature;
    }


    function get_sign_contents($uriWithQueryString, $requestBody, $clientId, $timeString)
    {
        $httpMethod = "POST";
        return $httpMethod . " " . $uriWithQueryString . "\n" . $clientId . "." . $timeString . "." . $requestBody;
    }

    function url_encode_signature($signature)
    {
        return urlencode(base64_encode($signature));
    }

    function url_decode_signature($encodedSignature)
    {
        return base64_decode(urldecode($encodedSignature));
    }


    function verify_signature($data, $signature, $publicKey)
    {
        $result = openssl_verify($data, $signature, $publicKey, OPENSSL_ALGO_SHA256);
        $this->trace('开始验签：');
        $this->trace($data);
        $this->trace($signature);
        $this->trace($result);
        if ($result == 1) {
            $this->trace('验签成功');
        } else {
            $this->trace('验签失败');
        }
        return $result;

    }

    //香港万里付
    public function notifyBillResult_hk()
    {
        $this->trace('notifyBillResult_hk');
        $this->notifyBillResult('worldfirst_hk');
    }

    function extractSignatureValue($signatureHeader)
    {
        if (!$signatureHeader) return null;

        $parts = explode(',', $signatureHeader);
        foreach ($parts as $part) {
            if (strpos($part, 'signature=') === 0) {
                return trim(substr($part, 10));
            }
        }
        return null;
    }

    //新加坡万里付
    public function notifyBillResult($type = 'worldfirst')
    {
        config('app_$this->trace', false);
        config('app_$this->debug', false);
        $dateTime = new \DateTime('now', new \DateTimeZone(config('app.default_timezone')));
        $timeString = $dateTime->format(\DateTime::ATOM);
        $uriWithQueryString = '/api/world_first/notifyBillResult';
        if ($type == 'worldfirst_hk') $uriWithQueryString = $uriWithQueryString . '_hk';

        $config = config($type);

        $privateKeyContent = $config['private_key_content'];
        $publicKeyContent = $config['public_key_content'];

        $clientId = $config['client_id'];
        $logFile = runtime_path() . 'log/' . $type . '_notify' . date('Ym') . '.log';

        @file_put_contents($logFile, date('Y-m-d H:i:s') . "\t" . $_SERVER['REMOTE_ADDR'] . PHP_EOL, FILE_APPEND);
        $requestBody = file_get_contents('php://input');
        $this->trace('request:' . $requestBody);
        @file_put_contents($logFile, $requestBody . PHP_EOL, FILE_APPEND);

//        验签
        $data = $this->get_sign_contents($uriWithQueryString, $requestBody, $clientId, $timeString);
        $headers = getallheaders();
        $signatureHeader = $headers['Signature'] ?? null;
        $signature = @$this->extractSignatureValue($signatureHeader);
        $this->trace('signature:' . $signature);
        $signatureBinary = @$this->url_decode_signature($signature);
        $verify = @$this->verify_signature($data, $signatureBinary, $publicKeyContent);
        @file_put_contents($logFile, $verify . PHP_EOL, FILE_APPEND);

        if ($verify == 0) {
            //验签失败则退出
//            return false;
        }

        if ($requestBody != '') {
            CardWorldfirstNotify::create(['params' => $requestBody]);
        }

        //如果包含账单数据orderNo则写交易记录
        if (strpos($requestBody, 'orderNo') !== false) {
            $requestData = json_decode($requestBody, true);
            if ($type == 'worldfirst_hk') {
                $requestData['card_bin'] = 13;
            } else {
                $requestData['card_bin'] = 10;
            }
            //调用万里付交易记录公用函数
            worldfirst_bill($requestData);
        }

        //如果包含账单数据passcode则写通知记录
        if (strpos($requestBody, 'passcode') !== false) {
            $requestData = json_decode($requestBody, true);
            $requestData['tradeAmount_currency'] = $requestData['tradeAmount']['currency'];
            $requestData['tradeAmount_value'] = $requestData['tradeAmount']['value'];
            unset($requestData['tradeAmount']);
            TransactionNotification::create($requestData);
        }

        //如果包含cardStatus,则更改卡片状态
        if (strpos($requestBody, 'cardStatus') !== false) {
            $requestData = json_decode($requestBody, true);
            $status = ($requestData['cardStatus'] == 'FROZEN') ? 0 : 1;
            $cardId = $requestData['assetId'];
            Card::where('card_id', $cardId)->update(['status' => $status]);
        }


        // 设置响应头
        $responseBody = json_encode(['result' => ['resultStatus' => 'S', 'resultCode' => 'SUCCESS', 'resultMessage' => 'success.']]);

        $data = $this->get_sign_contents($uriWithQueryString, $responseBody, $clientId, $timeString);
        $this->trace('begin...');
//        $this->trace($privateKeyContent);
        $privateKey = openssl_get_privatekey($privateKeyContent);
        $signatureBinary = $this->sign($data, $privateKey);
//        $this->verify_signature($data, $signatureBinary, $publicKeyContent);
        $urlEncodeSignature = $this->url_encode_signature($signatureBinary);
        $signHeader = "algorithm=RSA256,keyVersion=2,signature=" . $urlEncodeSignature;
        $this->trace($signHeader);
        $headers = [
            'Content-Type: application/json',
            "Signature: $signHeader",
            'Client-Id: ' . $clientId,
            'traceid:' . uniqid(),
            'Response-time: ' . $timeString,
        ];
        $this->trace($headers);
        foreach ($headers as $header) {
            header($header);
        }
        $this->trace('end...');
        echo $responseBody;
        exit;

    }

    private function trace($data)
    {
        $logFile = '/dev/shm/notify.log';
        $maxFileSize = 10 * 1024 * 1024; // 10MB

        if (is_array($data)) {
            $data = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
        }

        // 如果文件存在且超过10MB，重命名备份
        if (file_exists($logFile) && filesize($logFile) > $maxFileSize) {
            $backupFile = $logFile . '.bak';
            @rename($logFile, $backupFile);
        }

        $logLine = date('Y-m-d H:i:s') . "\t" . $data . PHP_EOL;
        @file_put_contents($logFile, $logLine, FILE_APPEND);
    }


}
